#include "Camera.hpp"
#include "CameraApi.h"
#include "CameraDefine.h"
#include "CameraStatus.h"
#include "Config.hpp"
#include <format>
#include <nlohmann/json.hpp>
#include <spdlog/spdlog.h>
#include <stdexcept>
#include <stop_token>

MindVisionCamera::MindVisionCamera(tSdkCameraDevInfo *cameraInfo) {
  if (CameraInit(cameraInfo, -1, -1, &handle) != CAMERA_STATUS_SUCCESS)
    throw std::runtime_error("MindVisionCamera Can't init camera");
  tSdkCameraCapbility capbility;
  MaxImageSize = capbility.sResolutionRange.iHeightMax *
                 capbility.sResolutionRange.iWidthMax * 3;
  UUID = std::format("MD{}", cameraInfo->acSn);
  config = new MindVisionConfig(handle);
}

MindVisionCamera::~MindVisionCamera() {
  CameraStop(handle);
  CameraUnInit(handle);
  delete config;
}

std::string MindVisionCamera::GetUUID() { return UUID; }

bool MindVisionCamera::ShotStatus() { return WorkThread.joinable(); }

BaseConfig *MindVisionCamera::Config() {
  return dynamic_cast<BaseConfig *>(config);
}

long MindVisionCamera::MaxSingleImgSize() { return MaxImageSize; }

float MindVisionCamera::FPS() {
  int fps;
  CameraGetFrameRate(handle, &fps);
  return fps;
}

void MindVisionCamera::StartShot() {
  WorkThread = std::jthread([this](std::stop_token token) {
    CameraPlay(handle);
    tSdkFrameHead frameInfo;
    unsigned char *buffer;
    nlohmann::json j = nlohmann::json::object();
    j["TimeStamp"] = 0;
    int frameID = 0;
    while (!token.stop_requested()) {
      int ret = CameraGetImageBuffer(handle, &frameInfo, &buffer, 3000);
      if (ret == CAMERA_STATUS_SUCCESS) {
        j["TimeStamp"] = frameInfo.uiTimeStamp;
        funcNewImage((long)frameID++, (char *)buffer, j.dump());
      } else {
        spdlog::info(std::format("Camera: {} CameraGetImageBuffer Failed : {}",
                                 UUID, ret));
      }
      CameraReleaseImageBuffer(handle, buffer);
    }
    CameraPause(handle);
  });
}

void MindVisionCamera::StopShot() {
  if (WorkThread.joinable()) {
    WorkThread.request_stop();
    WorkThread.join();
  }
}

BaseCamera::ImgInf MindVisionCamera::ShotImageType() {
  tSdkImageResolution resolution;
  CameraGetImageResolution(handle, &resolution);
  return {
      .width = resolution.iWidth,
      .height = resolution.iHeight,
      .type = ImageType::GREY,
      .size = resolution.iWidth * resolution.iHeight,
  };
}
